package 微信支付;

import cn.com.haiyunhui.common.core.exception.bisWarn.MyBizWarnException;
import cn.com.haiyunhui.common.core.web.domain.AjaxResult;
import cn.com.haiyunhui.handbusy.domain.business.GasWxConfig;
import cn.com.haiyunhui.handbusy.mapper.business.GasWxConfigMapper;
import cn.com.haiyunhui.handbusy.service.WxReconciliationService;
import cn.com.haiyunhui.handbusy.util.VxPayConfig;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Author: wx
 * @Date: 2023/10/25 9:23
 * @Description:
 */
@Service
@Slf4j
public class WxReconciliationServiceImpl implements WxReconciliationService {

    @Resource
    private GasWxConfigMapper wxConfigMapper;

    @Override
    public AjaxResult downloadBill(String time) {
        List<GasWxConfig> gasWxConfigs = wxConfigMapper.selectAll();
        for (GasWxConfig gasWxConfig : gasWxConfigs) {
            try {
                getUrl(gasWxConfig,time);
            } catch (Exception e) {
                log.error(gasWxConfig.getName() + "公司导出账单失败,时间:" + LocalDateTime.now() + "\n异常描述:" + e.getMessage());
            }
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult getIp(HttpServletRequest request) {

        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        log.info("=========================ip地址{}", ip);
        return AjaxResult.success("成功", ip);
    }


    public void getUrl(GasWxConfig gasWxConfig, String time) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //获取昨天时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, -1);
        String billDate = sdf.format(calendar.getTime());
        if (StrUtil.isNotBlank(time)){
            billDate = time;
        }
        //如果是ALL的话可以省略该参数
        String billType = "ALL";
        HttpGet httpGet = new HttpGet(String.format("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=%s&bill_type=%s", billDate, billType));


        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
        httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
        httpGet.addHeader("Accept", "*/*");

        VxPayConfig v = new VxPayConfig();
        BeanUtils.copyProperties(gasWxConfig, v);
        v.setAppid(gasWxConfig.getAppId());
        //TODO 测试使用的蒙城的
//        v.setPrivateKeyPath("F:\\project_3.x\\weixin-handbusy\\src\\main\\resources\\apiclient_key.pem");
        CloseableHttpClient httpClient = v.getWxPayClient(v.getVerifier(), v.getPrivateKey());
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200 || statusCode == 204) {
            log.info("申请账单成功, 返回结果:" + bodyAsString);
            // 2. 解析获取账单下载地址
            JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
            System.out.println(jsonObject.get("download_url").toString());

            downloadBill(billDate, jsonObject.get("download_url").toString(), gasWxConfig);
        } else {
            throw new MyBizWarnException("申请账单异常, 原因：" + bodyAsString);
        }
    }

    public void downloadBill(String billDate, String downloadUrl, GasWxConfig gasWxConfig) throws Exception {

        HttpGet httpGet = new HttpGet(downloadUrl);
        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
        httpGet.addHeader("Accept", "application/json");

        VxPayConfig v = new VxPayConfig();
        BeanUtils.copyProperties(gasWxConfig, v);
        //TODO 测试使用的蒙城的
//        v.setPrivateKeyPath("F:\\project_3.x\\weixin-handbusy\\src\\main\\resources\\apiclient_key.pem");

        // 设置一个空的应答签名验证器~ PS：下载账单时，微信没给应答签名，如果还验签会报错
        PrivateKey merchantPrivateKey = v.getPrivateKey();
        CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(gasWxConfig.getMchId(),
                        gasWxConfig.getMchSerialNo(),
                        merchantPrivateKey)
                .withValidator(response -> true)
                .build();

        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200 || statusCode == 204) {
            // 3. 本地存放
            byte[] bytes = EntityUtils.toByteArray(response.getEntity());
//            String path = "D:\\Users\\Downloads\\";
            String path = "/mnt/work/logs/downloads/weChat/";
            billDate = billDate.replaceAll("-", "");
            fileToBytes(bytes, path, gasWxConfig.getEpId() + "_" + billDate + ".csv");
            log.info("下载账单成功");
        } else {
            throw new MyBizWarnException("申请账单异常, 原因：" + bodyAsString);
        }
    }

    /**
     * 将Byte数组转换成文件
     *
     * @param bytes    byte数组
     * @param filePath 文件路径  如 D:\\Users\\Downloads\\
     * @param fileName 文件名
     */
    public static void fileToBytes(byte[] bytes, String filePath, String fileName) {
        log.info("准备存订单数据");
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file;
        try {
            log.info("生成文件");
            log.info("账单下载位置:{}", filePath + fileName);
            file = new File(filePath + fileName);
            file.createNewFile();
            log.info("生成文件成功-----开始写入数据");
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
            log.info("写入数据完成-------结束！！");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
